home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Mania 6
/
MacMania 6.toast
/
/
Multimedia & Desktop
/
sk8
/
SK8InJava
/
Code
/
Actors
/
Actor.java
next >
Encoding:
Amiga (detected)
Atari
Commodore
DOS
FM Towns/JPY
Macintosh
Macintosh JP
Macintosh to JP
NeXTSTEP
RISC OS/Acorn
Shift JIS
UTF-8
Wrap
Java Source
|
1997-02-27
|
38.3 KB
|
1,398 lines
|
[
TEXT/CWIE
]
/* SK8 © 1997 Apple Computer, Inc.
This code is protected under the current SK8 License
See http://sk8.research.apple.com/ for more information
Apple Research Laboratories
*/
import java.awt.*;
import java.applet.Applet;
public class actor {
//======================================================================
// constants.
//======================================================================
public static boolean debug = false;
// A mousedowneventmode that keeps getting reused.
static mousedowneventmode mousetrackingmode = new mousedowneventmode();
//======================================================================
// slots.
//======================================================================
public int filldirty = 0;
public int framedirty = 0;
renderer fillcolorVar = sk8.white;
renderer framecolorVar = sk8.black;
renderer textcolorVar = sk8.black;
int framesizeVar = 1;
String textVar = "";
Font textfontVar;
symbol textlocationVar = sk8.quote("CENTER");
//======================================================================
// Methods.
//======================================================================
public actor() {
super();
this.textfontVar = new Font("Geneva", Font.PLAIN, 9);
this.boundsrectVar = new Rectangle(0,0,20,20);
this.contentsVar = new list();
this.regionsDirty = true;
}
//======================================================================
// locking, making dirty, etc. Low level stuff.
//======================================================================
public stage stage () {
actor currentActor = this;
while (! ((currentActor instanceof stage) || (currentActor == null))) {
currentActor = currentActor.container();
}
return (stage)currentActor;
}
public int locklevel () {
stage stage = stage();
if (stage != null) {
return stage().locklevel();
} else return 0;
}
public void lock () {
stage stage = stage();
if (stage != null) {
stage.lock();
}
}
public void unlock () { unlock(false); }
public void unlock (boolean force) {
stage stage = stage();
if (stage != null) {
stage.unlock(force);
}
}
public void forceredraw () {
stage stage = stage();
if (stage != null) {
stage.canvas().forceRepaint();
}
}
private void addtodirtylist() {
stage stage = stage();
if (stage != null) {
stage.canvas().adddirtyactor(this);
}
}
public void makedirty () {
stage stage = stage();
if (stage != null) {
stagecanvas curCanvas = stage.canvas();
if ((filldirty == 0) || (framedirty == 0)) {
curCanvas.addRgnToUpdateRgn(this, boundsregion());
}
filldirty++;
framedirty++;
curCanvas.forceRepaint();
}
}
public void makefilldirty() {
stage stage = stage();
if (stage != null) {
stagecanvas curCanvas = stage.canvas();
if (filldirty == 0) {
curCanvas.addRgnToUpdateRgn(this, fillregion());
}
filldirty++;
curCanvas.forceRepaint();
}
}
public void makeframedirty() {
stage stage = stage();
if (stage != null) {
stagecanvas curCanvas = stage.canvas();
if (framedirty == 0) {
curCanvas.addRgnToUpdateRgn(this, frameregion());
}
framedirty++;
curCanvas.forceRepaint();
}
}
//======================================================================
// Container and contents
//======================================================================
protected list contentsVar = null;
public list contents () {
return contentsVar.copy();
}
private actor containerVar = null;
public actor container () {
return containerVar;
}
public void setcontainer (actor act) {
actor oldcontainer = containerVar;
if (oldcontainer != null) {
oldcontainer.contentsVar.removeElement(this);
oldcontainer.makedirty();
oldcontainer.lock();
}
containerVar = act;
if (act != null) {
act.lock();
act.contentsVar.push(this);
act.makedirty();
this.makedirty();
}
if (oldcontainer != null) oldcontainer.unlock();
if (act != null) act.unlock();
}
//======================================================================
// Layer
//======================================================================
public int layer () {
actor mycontainer = this.container();
if (mycontainer == null) {
return 1;
} else {
int pos = mycontainer.contentsVar.position(this);
if (pos == -1)
return 1;
else
return pos;
}
}
public void setlayer (int newlayer) {
actor mycontainer = this.container();
list peers = mycontainer.contentsVar;
if (mycontainer != null) {
if (newlayer <= 0) newlayer = 1; //bounds checking
int numactors = peers.length(); //bounds checking
if (newlayer > numactors) newlayer = numactors; //bounds checking
if (newlayer != this.layer()) { //if we are different then change the layer
peers.removeElement(this);
peers.insertnth(newlayer, this);
this.makedirty();
}
}
}
//Layer helper functions.
//Note that setlayer does all the required error checking.
public void bringtofront () {
this.setlayer(1);
}
public void bringcloser () {
this.setlayer(this.layer() - 1);
}
public void sendfurther () {
this.setlayer(this.layer() + 1);
}
public void sendtoback () {
actor mycontainer = this.container();
if (mycontainer != null) {
this.setlayer(mycontainer.contentsVar.length());
}
}
//======================================================================
// visible, hide and show.
//======================================================================
private boolean visibleVar = true;
public boolean visible () {
return visibleVar;
}
public void setvisible (boolean newvalue) {
visibleVar = newvalue;
makedirty();
}
public void hide () {
if (visibleVar == true) setvisible(false);
}
public void show () {
if (visibleVar == false) setvisible(true);
}
//======================================================================
// Boundsrect et.al.
//======================================================================
public Object resized () {
return null;
}
public Object moved () {
return null;
}
public Point physicaltological (Point location) {
actor currentActor = this;
Point containerLocation;
while (currentActor != null) {
if (currentActor instanceof stage)
containerLocation = new Point(0,0);
else
containerLocation = currentActor.location();
location.translate(- containerLocation.x, - containerLocation.y);
currentActor = currentActor.container();
}
return location;
}
public Point logicaltophysical (Point location) {
actor currentActor = this;
Point containerLocation;
while (currentActor != null) {
if (currentActor instanceof stage)
containerLocation = new Point(0,0);
else
containerLocation = currentActor.location();
location.translate(containerLocation.x, containerLocation.y);
currentActor = currentActor.container();
}
return location;
}
public Rectangle logicaltophysicalrect (Rectangle bounds) {
Point topleft = new Point(bounds.x, bounds.y);
this.logicaltophysical(topleft);
bounds.x = topleft.x;
bounds.y = topleft.y;
return bounds;
}
private Rectangle boundsrectVar = new Rectangle(0,0,20,20);
public Rectangle boundsrect () {
return new Rectangle(boundsrectVar.x, boundsrectVar.y, boundsrectVar.width, boundsrectVar.height);
}
public Rectangle boundsrect (boolean physical) {
if (physical == true) {
Rectangle mybounds = this.boundsrect();
actor mycontainer = this.container();
if ((mycontainer != null) && (! (mycontainer instanceof stage)))
mycontainer.logicaltophysicalrect(mybounds);
return mybounds;
} else
return this.boundsrect();
}
public void setboundsrect(int h, int v, int width, int height, boolean physical, boolean relative, boolean justmoving) {
int boundx, boundy, boundwidth, boundheight;
Rectangle mybounds = this.boundsrect();
if (relative == true) {
// if relative is true, physical does not matter since there is no scale.
boundx = h + mybounds.x;
boundy = v + mybounds.y;
boundwidth = width + mybounds.width;
boundheight = height + mybounds.height;
} else {
if (physical == true) {
// translate to logical.
Point logicalloc = new Point(h, v);
actor mycontainer = this.container();
if (mycontainer != null)
logicalloc = mycontainer.physicaltological(logicalloc);
boundx = logicalloc.x;
boundy = logicalloc.y;
} else {
boundx = h;
boundy = v;
}
boundwidth = width;
boundheight = height;
}
// All set. Do the work to update the regions and the screen
this.lock();
this.makedirty();
this.addtodirtylist();
boundsrectVar = new Rectangle(boundx, boundy, boundwidth, boundheight);
if (justmoving == true) {
int xoffset = mybounds.x - boundx;
int yoffset = mybounds.y - boundy;
this.offsetDeeply(xoffset, yoffset);
} else this.regionsDirty = true;
this.unlock();
}
//recursively offsets all of the inner contents regions by an x and y amount
private void offsetDeeply(int x, int y) {
this.offsetRegions(x, y);
list contents = this.contentsVar;
for(visitstate vs = contents.initialvisitstate(); vs != null; vs = contents.succeedingvisitstate(vs)) {
actor el = (actor) contents.elementatvisitstate(vs);
el.offsetDeeply(x, y);
}
}
public void setboundsrect (Rectangle r) {
this.setboundsrect(r.x, r.y, r.width, r.height, false, false, false);
}
public void setboundsrect (int x, int y, int width, int height) {
this.setboundsrect(x, y, width, height, false, false, false);
}
public void setboundsrect (int x, int y, int width, int height, boolean physical) {
this.setboundsrect(x, y, width, height, physical, false, false);
}
public void setboundsrect (collection bounds) {
setboundsrect(bounds, false, false);
}
public void setboundsrect (collection bounds ,boolean physical) {
setboundsrect(bounds, physical, false);
}
public void setboundsrect (collection bounds, boolean physical, boolean relative) {
int left = bounds.nthint(1);
int top = bounds.nthint(2);
int right = bounds.nthint(3);
int bottom = bounds.nthint(4);
this.setboundsrect(left, top, right - left, bottom - top, physical, relative, false);
}
// location.
public Point location () {
return this.location(false);
}
public Point location (boolean physical) {
Rectangle mybounds = this.boundsrect(physical);
return new Point (mybounds.x, mybounds.y);
}
public void setlocation (int h, int v, boolean physical, boolean relative) {
int width, height;
if (relative) {
width = 0;
height = 0;
} else {
Dimension curSize = this.size();
width = curSize.width;
height = curSize.height;
}
// call setboundsrect with justmoving = true.
this.setboundsrect(h, v, width, height, physical, relative, true);
}
public void setlocation (Point location) {
this.setlocation(location.x, location.y, false, false);
}
public void setlocation (Point location, boolean physical) {
this.setlocation(location.x, location.y, physical, false);
}
public void setlocation (collection location) {
int h = location.nthint(1);
int v = location.nthint(2);
Dimension mysize = this.size();
int left = h - (mysize.width / 2);
int top = v - (mysize.height / 2);
this.setlocation(left, top, false, false);
}
// size. Does not need to go through the boundsrect, but needs to because the user
// might redefine boundsrect to return esoteric values. Oh well... "SK8! Hooks everywhere!"
public Dimension size () {
return this.size(false);
}
public Dimension size (boolean physical) {
Rectangle mybounds = this.boundsrect();
// since we are not implementing scale physical can be ignored.
return new Dimension(mybounds.width, mybounds.height);
}
// Size should preserve the location!!!
public void setsize (int width, int height, boolean physical, boolean relative) {
Rectangle mybounds = this.boundsrect(physical);
int newleft, newtop;
if (relative == true) {
newleft = mybounds.x + (mybounds.width / 2) - (width + mybounds.width) / 2;
newtop = mybounds.y + (mybounds.height / 2) - (height + mybounds.height) / 2;
this.setboundsrect(newleft, newtop, width + mybounds.width, height + mybounds.height, physical, false, false);
} else {
newleft = mybounds.x + (mybounds.width / 2) - (width / 2);
newtop = mybounds.y + (mybounds.height / 2) - (height / 2);
this.setboundsrect(newleft, newtop, width, height, physical, relative, false);
}
}
public void setsize (int width, int height) {
this.setsize(width, height, false, false);
}
public void setsize (collection size) {
int width = size.nthint(1);
int height = size.nthint(2);
this.setsize(width, height, false, false);
}
// Functions for compatability with SK8
public list boundsrectlist () {
return boundsrectlist(false);
}
public list boundsrectlist (boolean physical) {
Rectangle rr = boundsrect(physical);
return sk8.list(rr.x, rr.y, rr.x + rr.width, rr.y + rr.height);
}
public void setboundsrectlist (collection bounds) {
setboundsrect(bounds, false, false);
}
public void setboundsrectlist (collection bounds ,boolean physical) {
setboundsrect(bounds, physical, false);
}
public void setboundsrectlist (collection bounds, boolean physical, boolean relative) {
setboundsrect(bounds, physical, relative);
}
public list locationlist () {
return locationlist(false);
}
public list locationlist (boolean physical) {
Rectangle rr = boundsrect(physical);
int h = rr.x + (rr.width / 2);
int v = rr.y + (rr.height / 2);
return sk8.list(h, v);
}
public list sizelist () {
return sizelist(false);
}
public list sizelist (boolean physical) {
Rectangle rr = boundsrect(physical);
return sk8.list(rr.width, rr.height);
}
// Height and Width helper functions
public int width() {
return this.boundsrect().width;
}
public void setwidth(int w) {
setsize(w, this.boundsrect().height, false, false);
}
public int height() {
return this.boundsrect().height;
}
public void setheight(int h) {
setsize(this.boundsrect().width, h, false, false);
}
// H and V helper functions for boundsrect
public int h() {
Rectangle rr = this.boundsrect();
int res;
res = rr.x + (rr.width / 2);
return res;
}
public void seth(int h) {
seth(h, false, false);
}
public void seth(int h, boolean physical) {
seth(h, physical, false);
}
public void seth(int h, boolean physical, boolean relative) {
setlocation(h, this.v(), physical, relative);
}
public int v() {
Rectangle rr = this.boundsrect();
int res;
res = rr.y + (rr.height / 2);
return res;
}
public void setv(int v) {
seth(v, false, false);
}
public void setv(int v, boolean physical) {
seth(v, physical, false);
}
public void setv(int v, boolean physical, boolean relative) {
setlocation(this.h(), v, physical, relative);
}
// Top, Right, Left, and Bottom helper functions *****NEED SETTERS
public int top() {
return top(false);
}
public int top(boolean physical) {
return this.boundsrect(physical).y;
}
public int left() {
return left(false);
}
public int left(boolean physical) {
return this.boundsrect(physical).x;
}
public int bottom() {
return bottom(false);
}
public int bottom(boolean physical) {
Rectangle rr = this.boundsrect(physical);
return rr.y + rr.height;
}
public int right() {
return right(false);
}
public int right(boolean physical) {
Rectangle rr = this.boundsrect(physical);
return rr.x + rr.width;
}
//======================================================================
// Highlight
//======================================================================
boolean highlightedVar = false;
public void dohighlight () {
this.lock();
this.setfillcolor(sk8.black);
this.settextcolor(sk8.white);
this.unlock();
}
public void dounhighlight () {
this.lock();
this.setfillcolor(sk8.white);
this.settextcolor(sk8.black);
this.unlock();
}
public boolean highlight () {
return this.highlightedVar;
}
// very simple, change the fillcolor to the highlight color.
// call dohighlight and dounhighlight to actually do it. This way
// people can redefine the method to get correct custom highlight
// behaviour.
public void sethighlight (boolean newvalue) {
if (newvalue != this.highlight()) {
this.highlightedVar = newvalue;
if (newvalue == true)
this.dohighlight();
else
this.dounhighlight();
}
}
boolean autohighlightVar = false;
public boolean autohighlight () {
return this.autohighlightVar;
}
public void setautohighlight (boolean newvalue) {
this.autohighlightVar = newvalue;
}
public void trackmousedown (actor originaltarget) {
this.sethighlight(true);
this.mousetrackingmode.originaltarget = originaltarget;
this.mousetrackingmode.entermode();
}
//======================================================================
// Fillcolor
//======================================================================
public renderer fillcolor () {
return fillcolorVar;
}
public void setfillcolor (renderer ren) {
fillcolorVar = ren;
makefilldirty();
}
//======================================================================
// Frame Stuff
//======================================================================
public renderer framecolor () {
return framecolorVar;
}
public void setframecolor (renderer ren) {
framecolorVar = ren;
makeframedirty();
}
public int framesize () {
return framesizeVar;
}
public list framesizelist () {
return sk8.list(framesizeVar, framesizeVar);
}
public void setframesize (int s) {
framesizeVar = s;
this.makedirty();
this.regionsDirty = true; // HMM DONT NEED TO RECOMPUTE BOUNDS IN THIS CASE, BUT WE ARE...
}
public void setframesize (list ll) {
int s = ll.nthint(1);
this.setframesize(s);
}
//======================================================================
// Text
//======================================================================
/* text */
public String text () {
if (textVar == null) {
textVar = "";
}
return textVar;
}
public void settext (String s) {
if (s == null) {
textVar = "";
} else {
textVar = s;
}
makefilldirty();
}
/* textcolor */
public renderer textcolor () {
return textcolorVar;
}
public void settextcolor (renderer ren) {
if (ren instanceof rgbcolor) {
textcolorVar = ren;
makefilldirty();
}
else
throw new RuntimeException("text color can only be an rgbcolor for now.");
}
/* textsize */
public int textsize () {
return textfontVar.getSize();
}
public void settextsize (int s) {
textfontVar = new Font(textfontVar.getName(), textfontVar.getStyle(), s);
makefilldirty();
}
/* textfont */
public String textfont () {
return textfontVar.getName();
}
public void settextfont (String name) {
textfontVar = new Font(name, textfontVar.getStyle(), textfontVar.getSize() );
makefilldirty();
}
/* textstyle */
public int textstyle () {
return textfontVar.getStyle();
}
public void settextstyle (int s) {
textfontVar = new Font(textfontVar.getName(), s, textfontVar.getSize());
makefilldirty();
}
public void settextstyle (list newvalue) {
//***NEED TO IMPLEMENT THIS!!!!
throw new RuntimeException("Not Implemented: For now, set the text style to a JAVA style (an integer).");
}
// textlocation.
public symbol textlocation () {
return this.textlocationVar;
}
public void settextlocation (symbol newvalue) {
this.textlocationVar = newvalue;
clearTextLocationInfo();
this.makefilldirty();
}
// ActorTextSize
public Point actortextsize () {
Graphics g = sk8.stage.canvas().getGraphics();
g.setFont(this.textfontVar);
return this.actortextsize(g);
}
public Point actortextsize(Graphics g, String s, boolean ExcludeDescent) {
FontMetrics fm = g.getFontMetrics(this.textfontVar);
int height = fm.getHeight();
int width = fm.stringWidth(s);
if (ExcludeDescent == true)
height -= fm.getDescent();
return new Point(width, height);
}
public Point actortextsize(Graphics g, String s) {
return actortextsize(g, s, false);
}
public Point actortextsize(Graphics g) {
return actortextsize(g, textVar, false);
}
public Point actortextsize(Graphics g, boolean ExcludeDescent) {
return actortextsize(g, textVar, ExcludeDescent);
}
//======================================================================
// Drawing
//======================================================================
//-------------------------------------------------------------------------
//-------------------------------------------------------------------------
public Region makeboundsregion() {
Region reg = new Region();
Rectangle myBR = boundsrect(true);
reg.setRectRegion(myBR.x, myBR.y, myBR.width, myBR.height);
return reg;
}
public Region makefillregion() {
Region reg = new Region();
Rectangle myBR = boundsrect(true);
myBR.x += framesizeVar;
myBR.y += framesizeVar;
myBR.width -= 2 * framesizeVar;
myBR.height -= 2 * framesizeVar;
reg.setRectRegion(myBR.x, myBR.y, myBR.width, myBR.height);
return reg;
}
public Region makeframeregion() {
if (framesizeVar > 0) {
Region br = boundsregion().copy();
br.diffRegion(fillregion());
return br;
} else {
return new Region();
}
}
private void offsetRegions (int dx, int dy) {
if ((boundsregionVar != null) && (regionsDirty != true)) boundsregionVar.offsetRegion(dx,dy);
if ((fillregionVar != null) && (regionsDirty != true)) fillregionVar.offsetRegion(dx,dy);
if ((frameregionVar != null) && (regionsDirty != true)) frameregionVar.offsetRegion(dx,dy);
}
private Region boundsregionVar = null;
private boolean regionsDirty = true;
public Region boundsregion() {
if ((boundsregionVar == null) || (regionsDirty == true))
boundsregionVar = makeboundsregion();
return boundsregionVar;
}
private Region fillregionVar = null;
public Region fillregion() {
if ((fillregionVar == null) || (regionsDirty == true)) {
fillregionVar = makefillregion();
clearTextLocationInfo();
}
return fillregionVar;
}
private Region frameregionVar = null;
public Region frameregion() {
if ((frameregionVar == null) || (regionsDirty == true))
frameregionVar = makeframeregion();
return frameregionVar;
}
public void clipRegionToAllContainers (Region rgn) {
actor currentActor = this.container();
while (currentActor != null) {
rgn.sectRegion(currentActor.fillregion());
currentActor = currentActor.container();
}
}
public void draw (Graphics g, Region drawRegion) {
filldirty = 0;
framedirty = 0;
if ((visible() == true) && (! drawRegion.isEmptyRegion())) {
//Check to see if the frame is dirty
if (framesizeVar > 0) {
Region frameToDraw = drawRegion.copy();
frameToDraw.sectRegion(frameregion());
//If so we render the part of it that intersects the draw region
if (! frameToDraw.isEmptyRegion())
framecolor().render(g, this, frameToDraw);
}
//Now the Fill Region
//We check first to make sure it is dirty and needs drawing
//Note that since the fill is all that remains
//we can just the region object we were passed to do the rest of the work.
//therefore we don't have to make another copy like we did with the frame.
Region fillToDraw = drawRegion;
fillToDraw.sectRegion(fillregion());
//If there is anything to draw..
if (! fillToDraw.isEmptyRegion()) {
// First draw the contents
list contents = this.contentsVar;
if (! contents.empty()) {
for(visitstate vs = contents.initialvisitstate();
((vs != null) && (! drawRegion.isEmptyRegion()));
vs = contents.succeedingvisitstate(vs)) {
//For each subActor
actor subActor = (actor) contents.elementatvisitstate(vs);
//Generate a new draw region which is the part
//that's over the subActor
if ((subActor.visible() == true) && (subActor.boundsregion().bboxIntersects(drawRegion) == true)) {
Region clippedDrawRegion = subActor.boundsregion().copy();
clippedDrawRegion.sectRegion(drawRegion);
//Then draw it
subActor.draw(g, clippedDrawRegion);
//And then remove that piece from our draw region
drawRegion.diffRegion(subActor.boundsregion());
}
}
}
//Then the background
//Which is now the part of our fillregion that is not covered
//by things that needed to be drawn
fillcolor().render(g, this, drawRegion);
}
//And then the text overtop no matter what.
//**** We'd like to clip THIS to the draw region too, but cant yet...
if (this.text().length() > 0)
drawtext(g);
}
}
// This code computes the proper x, y location for the text to be drawn
// We optimize this by recomputing the point at draw time only after the setting
// of textlocation and boundsrect and framesize
private Point textLocDrawPoint; // For storing the point
private void clearTextLocationInfo () { //For signalling that the point needs to be recomputed
textLocDrawPoint = null;
}
private void computeTextLocation (Graphics g) {
//Now we will compute the proper x, y location for the text to be drawn
int x = 0, y = 0;
// First, we get the font information. All at one time, no need to call
// actortextsize.
FontMetrics fm = g.getFontMetrics(this.textfontVar);
int height = fm.getHeight();
int width = fm.stringWidth(this.textVar);
int descent = fm.getDescent();
int ascent = fm.getAscent();
//Then, we compute the fill region's rectangle
Rectangle myBR = boundsrect(true);
// now deal with the nine cases for positioning.
if (this.textlocationVar == sk8.quote("TOPLEFT")) {
x = 3 + myBR.x;
y = myBR.y + height;
} else if (this.textlocationVar == sk8.quote("TOPCENTER")) {
x = myBR.x + (myBR.width / 2) - (width / 2);
y = myBR.y + ascent + 5; // height
} else if (this.textlocationVar == sk8.quote("TOPRIGHT")) {
x = (myBR.x + myBR.width) - width;
y = myBR.y + height;
} else if (this.textlocationVar == sk8.quote("CENTERLEFT")) {
x = 3 + myBR.x;
y = myBR.y + (myBR.height / 2); // - ((height + descent) / 2);
} else if (this.textlocationVar == sk8.quote("CENTER")) {
x = myBR.x + (myBR.width / 2) - (width / 2);
y = myBR.y + (myBR.height / 2) + descent;// - (height / 2);
} else if (this.textlocationVar == sk8.quote("CENTERRIGHT")) {
x = (myBR.x + myBR.width) - width;
y = myBR.y + (myBR.height / 2);// - ((height + descent) / 2);
} else if (this.textlocationVar == sk8.quote("BOTTOMLEFT")) {
x = 3 + myBR.x;
y = myBR.y + myBR.height - descent;
} else if (this.textlocationVar == sk8.quote("BOTTOMCENTER")) {
x = myBR.x + (myBR.width / 2) - (width / 2);
y = myBR.y + myBR.height - descent;
} else if (this.textlocationVar == sk8.quote("BOTTOMRIGHT")) {
x = (myBR.x + myBR.width) - width;
y = myBR.y + myBR.height - descent;
}
textLocDrawPoint = new Point(x, y);
}
public void drawtext(Graphics curGraph) {
//First we remove any old clip regions
Graphics g = curGraph.create();
Rectangle myBR = fillregion().getBBox();
g.clipRect(myBR.x, myBR.y, myBR.width, myBR.height);
//And set up the textfont and text color
rgbcolor curtextcolor = (rgbcolor) this.textcolorVar;
g.setColor(curtextcolor.currentColor);
g.setFont(this.textfontVar);
//Now compute the x, y location for the text to be drawn
if (textLocDrawPoint == null)
computeTextLocation(g);
// Now finally draw the text draw the text!
g.drawString(textVar, textLocDrawPoint.x, textLocDrawPoint.y);
}
/*
//======================================================================
// Window Stuff
//======================================================================
String windowtitleVar = "";
public String windowtitle () {
return this.windowtitleVar;
}
public void setwindowtitle (String newvalue) {
this.windowtitleVar = newvalue;
if (this.container() == sk8.stage) {
actorwindow curwindow = getwindow();
if (curwindow != null) curwindow.setTitle(newvalue);
}
}
int cursorVar= Frame.DEFAULT_CURSOR;
public int cursor () {
return this.cursorVar;
}
public void setcursor (int newvalue) {
this.cursorVar = newvalue;
if (this.container() == sk8.stage) {
actorwindow curwindow = getwindow();
if (curwindow != null) curwindow.setCursor(newvalue);
}
}
*/
//======================================================================
// MouseSensitivity
//======================================================================
symbol mousesensitivityVar = sk8.quote("NORMAL");
public symbol mousesensitivity () {
return this.mousesensitivityVar;
}
public void setmousesensitivity (symbol newvalue) {
this.mousesensitivityVar = newvalue;
}
//======================================================================
// DoFirstClick NEEDS TO BE IMPLEMENTED
//======================================================================
boolean dofirstclickVar = false;
public boolean dofirstclick () {
return this.dofirstclickVar;
}
public void setdofirstclick (boolean newvalue) {
this.dofirstclickVar = newvalue;
}
//======================================================================
// Dispatching mouseenter and mouseleave...
//======================================================================
// returns the depth of the actor in the containment hierarchy. If the
// actor is not on the Stage, this returns 0.
public int depth () {
actor anactor = this;
int result = 1;
while (true) {
if ((anactor == null) || (anactor instanceof stage))
return result;
result = result + 1;
anactor = anactor.container();
}
}
actor findcommoncontainer (actor shallowactor, int depthdelta) {
actor deepactor = this;
// [1] bring them to the same depth.
int i;
for (i = 0; i < depthdelta; i++) {
if (deepactor == null) return null;
deepactor = deepactor.container();
}
// [2] search and return when equal.
while (true) {
if ((deepactor == sk8.stage) || (deepactor == null) || (shallowactor == null))
return sk8.stage;
if (deepactor == shallowactor)
return deepactor;
deepactor = deepactor.container();
shallowactor = shallowactor.container();
}
}
// call mouseenter on each item in the path from commoncontainer to this (the actor).
// use recursion to make the reverse calling happen.
void reverseddispatchmouseenter (actor commoncontainer) {
if (this != commoncontainer) {
if ((this.container() != null) && (commoncontainer != null)) {
((actor)(this.container())).reverseddispatchmouseenter(commoncontainer);
this.mouseenter();
}
}
}
// this = the old actor, the one that should get a mouseleave.
// This function dispatches mouseEnter and mouseLeave events. MouseLeave is sent to
// all actors from oldActor to the commonContainer (not including the commonContainer).
// MouseEnter is sent to all actors on the path from the commonContainer (not including it) to
// newActor.
// An important side effect of all this is that for every actor except newActor, mouseEnter
// will be called and the eventActor will not be itself!!! Also that mouseEnter
// cannot be propagated up the hierarchy.
// MouseLeave is done from the bottom up and mouseEnter from the top down.
void dispatchmouseenterandleave(actor newactor) {
actor oldactor = this;
int olddepth = ((actor) oldactor).depth();
int newdepth = ((actor) newactor).depth();
actor commoncontainer;
// if the actor is no longer on the stage, do not send mouseleaves to it.
if (newdepth == 0)
((actor)newactor).reverseddispatchmouseenter(sk8.stage);
else {
// [1] find common container.
if (olddepth > newdepth)
commoncontainer = ((actor) oldactor).findcommoncontainer(newactor, olddepth - newdepth);
else
commoncontainer = ((actor) newactor).findcommoncontainer(oldactor, newdepth - olddepth);
// [2] Dispatch mouseleave (from deepest up).
while (true) {
if ((oldactor == commoncontainer) || (oldactor == null)) break;
oldactor.mouseleave();
oldactor = oldactor.container();
}
// [3] set the event actor.
sk8.stage.eventactorVar = newactor;
// [4] Dispatch mouseenter (from shallowest up).
((actor) newactor).reverseddispatchmouseenter(commoncontainer);
}
}
// When the oldActor was nil, we throw up our arms. We just set the eventActor and
// dispatch mouseEnter to everything from the Stage up to the new actor.
void justdomouseenters () {
// [1] set the event actor.
sk8.stage.eventactorVar = this;
// [2] send the mouse enters.
this.reverseddispatchmouseenter(sk8.stage);
}
// this is the new event target.
void changeeventactor () {
if (sk8.stage.eventactorVar != null)
((actor)(sk8.stage.eventactorVar)).dispatchmouseenterandleave(this);
else
this.justdomouseenters();
}
//======================================================================
// Event System
//======================================================================
// pointonwhichactor
// Figuring out the event actor using mousesensitivity!!!
// this = the window where we start the search.
// x and y are given in window coordinates.
public actor hitbymouse (int h, int v) {
return null;
}
public actor pointonwhichactor (int x, int y) {
return pointonwhichactor(x, y, null);
}
public actor pointonwhichactor (int x, int y, actor avoiding) {
actor targethit = this;
symbol mousesensitivity = this.mousesensitivity();
if ((this.visible() == true) &&
(this != avoiding) &&
(mousesensitivity != sk8.quote("INVISIBLE")) &&
(this.boundsregion().isInside(x,y)) //(this.boundsrect(true).inside(x,y)))
) {
// At this point actor has been physically hit. If it has custom mouse sensitivity,
// we call its method to find out who has been hit. The custom method handles
// examining the contents and thus we jump this step in this case.
if (mousesensitivity == sk8.quote("CUSTOM")) {
targethit = this.hitbymouse(x,y);
} else {
// Does it pass mouse events and does it have contents to pass them to?
// and it does not have custom sensitivity.
if ((mousesensitivity != sk8.quote("OPAQUE")) && (! this.contentsVar.empty())) {
// YES: check each actor in contents.
list contents = this.contentsVar;
for(visitstate vs = contents.initialvisitstate(); vs != null; vs = contents.succeedingvisitstate(vs)) {
actor thing = (actor) contents.elementatvisitstate(vs);
actor contenthit = thing.pointonwhichactor(x, y, avoiding);
if (contenthit != null) return contenthit;
}
}
}
// if we got here, no subactor was hit. Then this actor is the most
// specific actor hit and we are done. We return it, unless it is mouseTransparent.
if ((targethit != null) && (mousesensitivity != sk8.quote("TRANSPARENT"))) {
return targethit;
}
}
return null;
}
// Event handlers.
void sk8idleevent (Event e) {
}
void sk8selectoldwindow (Event e, actor previouswindow) {
if (previouswindow != null)
previouswindow.deactivate();
if (sk8.eventwindow() != null)
sk8.eventwindow().activate();
}
void sk8mousedownevent (Event e) {
actor curEventActor = sk8.eventactor();
if (curEventActor != null) {
//actor eventtarget = this.window().pointonwhichactor(sk8.stage.eventh(), sk8.stage.eventv());
if (debug) sk8.sendtolog("Actor found at [" + sk8.eventh() + "," + sk8.eventv() + "] was " + curEventActor);
curEventActor.mousedown();
// Send clicks and doubleclicks: doubleclickstyle = 'normal'.
if (e.clickCount == 1) {
curEventActor.click();
} else if (e.clickCount == 2) {
curEventActor.click();
curEventActor.doubleclick();
}
}
}
void sk8mouseupevent (Event e) {
if (sk8.eventactor() != null)
sk8.eventactor().mouseup();
}
void sk8keydownevent (Event e) {
if (sk8.eventactor() != null)
sk8.eventactor().keydown((char) e.key);
}
void sk8keyupevent (Event e) {
if (sk8.eventactor() != null)
sk8.eventactor().keyup((char) e.key);
}
// High level actor handlers: standard SK8 Suite.
public Object mouseenter () {
// do NOT pass to the container!!!
return null;
}
public Object mouseleave () {
// do NOT pass to the container!!!
return null;
}
public Object mousedown () {
// do autohighlight behaviour.
if (this.autohighlight() == true)
trackmousedown(this);
// propagate up the containment hierarchy.
actor mycontainer = this.container();
if (mycontainer != null) {
mycontainer.mousedown();
}
return null;
}
public Object mouseup () {
actor mycontainer = this.container();
if (mycontainer != null) {
mycontainer.mouseup();
}
return null;
}
public Object click () {
actor mycontainer = this.container();
if (mycontainer != null) {
mycontainer.click();
}
return null;
}
public Object doubleclick () {
actor mycontainer = this.container();
if (mycontainer != null) {
mycontainer.doubleclick();
}
return null;
}
public Object keyup (char thekey) {
return null;
}
public Object keydown (char thekey) {
return null;
}
public Object activate () {
return null;
}
public Object deactivate () {
return null;
}
//======================================================================
// Dragging.
//======================================================================
public Object drag () {
return this.drag(false);
}
public Object drag (boolean withEvents) {
dragresizeeventmode em = new dragresizeeventmode(this, false, withEvents);
em.entermode();
return null;
}
public Object dragged () {
return null;
}
public Object draggingmousewithin (actor actordragged) {
return null;
}
public Object draggingmouseenter (actor actordragged) {
return null;
}
public Object draggingmouseleave (actor actordragged) {
return null;
}
public Object drop (actor droprecipient) {
droprecipient.dropped(this);
return null;
}
public Object dropped (actor droppee) {
return null;
}
//======================================================================
// RESIZING
//======================================================================
boolean resizableVar = true;
public boolean resizable () {
return this.resizableVar;
}
public void setresizable (boolean resi) {
this.resizableVar = resi;
}
public Object resize () {
return resize(sk8.quote("BOTTOMRIGHT"));
}
public Object resize (symbol loc) {
dragresizeeventmode em = new dragresizeeventmode(this, true, false);
em.entermode();
return null;
}
public Object resizedone () {
return null;
}
}